package com.ccteam.fluidmusic.fluidmusic.common.utils

import android.os.Bundle
import android.os.Parcelable
import android.os.ResultReceiver
import androidx.core.os.bundleOf
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.trackselection.MappingTrackSelector
import com.orhanobut.logger.Logger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize

/**
 * @author Xiaoc
 * @since 2021/4/20
 *
 * 自定义的比特率音质获取的自定义MediaController命令
 */
class BitrateTrackCommandReceiver(
    private val trackSelector: DefaultTrackSelector
): MediaSessionConnector.CommandReceiver {

    // 协程组件
    private val serviceJob = SupervisorJob()
    private val serviceScope = CoroutineScope(Dispatchers.Main + serviceJob)

    companion object{
        const val COMMAND_SELECT_BITRATE = "fluidmusic_select_bitrate"
        const val COMMAND_UPDATE_BITRATE = "fluidmusic_update_bitrate"
        const val COMMAND_UPDATE_RENDER_INDEX = "fluidmusic_update_render_index"

        const val SELECT_BITRATE_COMMAND_SUCCESS = 0x102
        const val SELECT_BITRATE_COMMAND_FAIL = 0x105
        const val UPDATE_BITRATE_COMMAND_SUCCESS = 0x107
        const val UPDATE_BITRATE_COMMAND_FAIL = 0x109
    }

    override fun onCommand(
        player: Player,
        controlDispatcher: ControlDispatcher,
        command: String,
        extras: Bundle?,
        cb: ResultReceiver?
    ): Boolean {
        if(COMMAND_SELECT_BITRATE != command && COMMAND_UPDATE_BITRATE != command){
            return false
        }
        serviceScope.launch(Dispatchers.Default) {

            try {
                if(command == COMMAND_SELECT_BITRATE){
                    selectBitrateTrack(cb)
                } else if(command == COMMAND_UPDATE_BITRATE){
                    val trackData = extras?.getParcelable<BitrateTrackData>(COMMAND_UPDATE_BITRATE) ?: return@launch
                    val renderIndex = extras.getInt(COMMAND_UPDATE_RENDER_INDEX)

                    updateBitrateTrack(cb,trackData,renderIndex)
                }
            } catch (e: Exception){
                if(command == COMMAND_SELECT_BITRATE){
                    cb?.send(SELECT_BITRATE_COMMAND_FAIL,null)
                } else {
                    cb?.send(UPDATE_BITRATE_COMMAND_FAIL,null)
                }
            }

        }
        return true
    }

    private fun selectBitrateTrack(cb: ResultReceiver?){
        cb ?: return
        val mappedTrackInfo = trackSelector.currentMappedTrackInfo ?: run{
            cb.send(SELECT_BITRATE_COMMAND_FAIL,null)
            return
        }
        val trackInfoList = mutableListOf<TrackInfo>()
        for (renderIndex in 0 until mappedTrackInfo.rendererCount){
            if(isSupportedTrackType(mappedTrackInfo,renderIndex)){
                val trackGroups = mappedTrackInfo.getTrackGroups(renderIndex)

                val overrides = trackSelector.parameters.getSelectionOverride(renderIndex,trackGroups)

                val bitrateList = mutableListOf<BitrateTrackData>()
                for(groupIndex in 0 until trackGroups.length){
                    val trackGroup = trackGroups.get(groupIndex)

                    for(trackIndex in 0 until trackGroup.length){
                        val bitrate = trackGroup.getFormat(trackIndex).bitrate
                        if(bitrate <= 0){
                            break
                        }
                        bitrateList.add(
                            BitrateTrackData(
                                groupIndex,trackIndex,
                                bitrate,
                                mappedTrackInfo.getTrackSupport(renderIndex,groupIndex,trackIndex) == C.FORMAT_HANDLED,
                                overrides?.containsTrack(trackIndex) ?: false
                            )
                        )
                    }
                }
                // 加入自动的比特率类别
                bitrateList.add(0, BitrateTrackData(
                    -1,-1,-1,true,overrides == null)
                )
                trackInfoList.add(TrackInfo(renderIndex,bitrateList))
            }
        }

        cb.send(SELECT_BITRATE_COMMAND_SUCCESS, bundleOf(COMMAND_SELECT_BITRATE to trackInfoList))
    }

    private fun updateBitrateTrack(cb: ResultReceiver?,trackData: BitrateTrackData,renderIndex: Int){
        cb ?: return
        val trackGroups = trackSelector.currentMappedTrackInfo?.getTrackGroups(renderIndex) ?: run{
            cb.send(UPDATE_BITRATE_COMMAND_FAIL,null)
            return
        }

        // 如果groupIndex或trackIndex为负数，则代表为自动调整，将其置为null即为自动调整比特率
        val overrides = if(trackData.groupIndex < 0 || trackData.trackIndex < 0){
            null
        } else {
            DefaultTrackSelector.SelectionOverride(
                trackData.groupIndex,trackData.trackIndex
            )
        }

        val builder = trackSelector.buildUponParameters()
        builder
            .clearSelectionOverrides(renderIndex)

        // 如果overrides为null，代表自动调整，不进行设置Override，只需清理渲染
        if(overrides != null){
            builder.setSelectionOverride(
                renderIndex,trackGroups,
                overrides
            )
        }

        trackSelector.setParameters(builder)
        cb.send(UPDATE_BITRATE_COMMAND_SUCCESS,null)
    }

    private fun isSupportedTrackType(mappedTrackInfo: MappingTrackSelector.MappedTrackInfo,
                                     renderIndex: Int): Boolean{
        val trackGroups = mappedTrackInfo.getTrackGroups(renderIndex)
        if(trackGroups.length == 0){
            return false
        }
        val trackType = mappedTrackInfo.getRendererType(renderIndex)
        return trackType == C.TRACK_TYPE_AUDIO
    }
}

@Parcelize
data class TrackInfo(
    val renderIndex: Int,
    val bitrateList: List<BitrateTrackData>
): Parcelable

@Parcelize
data class BitrateTrackData(
    val groupIndex: Int,
    val trackIndex: Int,
    val bitrate: Int,
    val isSupported: Boolean,
    val selected: Boolean
): Parcelable